<?php
namespace Martdb;


use Thrift\Transport\TSocket;
use Thrift\Transport\TFramedTransport;
use Thrift\Protocol\TBinaryProtocol;
use Martdb\Libs\MartdbRequest;
use Thrift\Exception\TException;
use Martdb\Libs\MartdbServiceClient;
use Illuminate\Support\Facades\Config;
use Illuminate\Config\Repository;
use Martdb\Libs\MartdbResponse;
use Martdb\Utils\TList;
use Martdb\Utils\CodedOutputStream;
use Martdb\Utils\TMap;
use Martdb\Utils\CodedInputStream;

/**
 * Class MartdbClient
 *
 */
class MartdbClient
{
    
    /**
     * Martdb -服务
     * @var unknown
     */
    private $_client;
    
    
    /**
     * 配置项
     * @var unknown
     */
    private $config;
    
    
    /**
     * 传输
     * @var unknown
     */
    private $_transport;
    
    
    /**
     * 协议
     * @var unknown
     */
    private $_protocol;
    
    
    
    
    /**
     * 
     * @author	 田小涛
     * @datetime 2020年12月11日 上午11:53:28
     * @comment	
     *
     */
    public function __construct( $server = null, $port = null )
    {
        
        $strServer = Config::get( 'martdb.service' );
        if( isset( $server ) && !is_null( $server ) && strlen( $server ) > 0 )
        {
            $strServer = $server;
        }

        $strPort = Config::get( 'martdb.port' );
        if( isset( $port ) && !is_null( $port ) && strlen( $port ) > 0 )
        {
            $strPort = $port;
        }

        $socket = new TSocket( $strServer, $strPort );
		if( Config::get( 'martdb.sendtime' ) )
        {
            $socket->setSendTimeout( Config::get( 'martdb.sendtime' ) );
        }
        if( Config::get( 'martdb.rectime' ) )
        {
            $socket->setRecvTimeout( Config::get( 'martdb.rectime' ) );
        }
        
        $this->_transport = new TFramedTransport( $socket );
        $this->_protocol = new TBinaryProtocol( $this->_transport );
        
        $this->_initClient();
    }
    
    
    /**
     * 初始化 —— Martdb 服务
     * @author	 田小涛
     * @datetime 2020年12月11日 上午11:56:18
     * @comment	
     * 
     * @param unknown $transport
     * @param unknown $protocol
     */
    private function _initClient()
    {
        
        try {
            $this->_transport->open();
            $this->_client = new MartdbServiceClient( $this->_protocol );
        } catch ( Exception $e ) {
            throw $e;
        } catch ( TException $tx ) {
            throw $tx;
        }
        
    }
    
    
    
    
    /**
     * 将参数转换为字节数组
     * @author	 田小涛
     * @datetime 2020年12月11日 下午1:42:06
     * @comment	
     * 
     * @param unknown $list
     * @param string $returnBytes
     * @return array
     */
    public function toBytes( $list, $returnBytes = false )
    {
        if ( is_null( $list ) )
        {
            $list = new TList();
        }
        
        $out = new CodedOutputStream();
        $out->writeCollection( $list );
        $out->flush();
        
        return $returnBytes ? $out->getOutput() : $out->output();
    }
    
    
    
    /**
     * 将参数转换为对象
     * @author	 田小涛
     * @datetime 2020年12月11日 下午1:42:25
     * @comment	
     * 
     * @param unknown $buf
     * @return \Martdb\TMap|\martdb\TMap
     */
    public function toObject( $buf ) 
    {
        if ( is_null( $buf ) ) 
        {
            return new TMap();
        }
        
        $input = new CodedInputStream( $buf );
        
        return $input->readMap();
    }
    
    
    
    /**
     * 获取当前系统时间的毫秒数
     * @author	 田小涛
     * @datetime 2020年12月11日 下午1:48:25
     * @comment	
     * 
     * @return number
     */
    public function currentTimeMillis()
    {
        list($msec, $sec) = explode(' ', microtime());
        $msectime =  (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
        
        return $msectime;
    }
    
    
    
    
    
    /**
     * 获取请求句柄
     * @author	 田小涛
     * @datetime 2020年12月11日 下午2:19:47
     * @comment	
     * 
     * @param unknown $service
     * @return \martdb\MartdbRequest
     */
    public function requestHandle( $config = array() )
    {
        if( !isset( $config[ 'tag' ] ) )
        {
            throw new \Exception( 'Undefind Param 【tag】' );
            
            return false;
        }
        
        if( isset( $config[ 'id' ] ) )
        {
            $arrParams[ 'id' ]      = $config[ 'id' ];
        }
        else
        {
            $arrParams[ 'id' ]      = uniqid( md5(microtime(true)), true );
        }
        $arrParams[ 'sender' ]  = Config::get( 'martdb.sender' );
        $arrParams[ 'time' ]    = $this->currentTimeMillis();
        
        if( isset( $config[ 'tag' ] ) )
        {
            $arrParams[ 'tag' ]      = $config[ 'tag' ];
        }
        if( isset( $config[ 'method' ] ) )
        {
            $arrParams[ 'method' ] = $config[ 'method' ];
        }
        
        return new MartdbRequest( $arrParams );
    }
    
    
    
    /**
     * 执行
     * @author	 田小涛
     * @datetime 2020年12月11日 下午2:24:25
     * @comment	查询数据+数据解析
     * 
     * @param MartdbRequest $request
     * @throws \Exception
     * @return unknown|boolean
     */
    public function execute( MartdbRequest $request )
    {
        $objResult = new \stdClass();
        try {
            $response = $this->_client->execute( $request );
            
            $objResult = $this->formatResult( $response );
            unset( $response );
        } catch ( Exception $e ) {
            
            throw new \Exception( 'Error during operation: ' .$e->getMessage() );
        }
        $this->_transport->close();
        
        return $objResult;
    }
    
    
    /**
     * 解析结果
     * @author	 田小涛
     * @datetime 2020年12月14日 下午3:33:03
     * @comment
     *
     * @param MartdbResponse $res
     */
    protected function formatResult( $res )
    {
        $objRet = new \stdClass();
        $objRet->id         = $res->id;
        $objRet->request_id = $res->request_id;
        if( '0' == $res->code && $res->result )
        {
            $objInfo = $this->toObject( $res->result );
            $objRet->datas = $objInfo->get( 'data' );
            
            unset( $objInfo );
        }
        $objRet->msg = $res->msg;
        
        unset( $res );
        return $objRet;
    }
    
}

